package cn.chenc.framework.core.util;


import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.util.StringUtils;

import java.lang.management.ManagementFactory;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.util.*;
import java.util.regex.Pattern;

public class DateUtils extends org.apache.commons.lang3.time.DateUtils{
    public static final String YYYYMMDDHHMMSS = "yyyy-MM-dd HH:mm:ss";
    public static final String YYYYMMDD = "yyyy-MM-dd";
    public static final String YYYYMMDDHHMM = "yyyy-MM-dd HH:mm";
    public static final String YYYYMM = "yyyy-MM";

    private static String[] parsePatterns = {
            "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
            "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
            "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};



    /**
     * 获取当前Date型日期
     *
     * @return Date() 当前日期
     */
    public static Date getNowDate() {
        return new Date();
    }

    /**
     * 获取服务器启动时间
     */
    public static Date getServerStartDate()
    {
        long time = ManagementFactory.getRuntimeMXBean().getStartTime();
        return new Date(time);
    }

    /**
     * @description: 获取当前日期字符串
     * @param var1 日期格式(例如："yyyy-MM-dd HH:mm:ss")
     * @return java.lang.String
     * @throws
     * @author secret
     * @date 2020/12/12 secret
     */
    public static String getCurrentDate(String var1) {
        return (new SimpleDateFormat(var1)).format(new Date());
    }

    /**
     * @description: 将日期字符串转化为Date对象
     * @param date 日期字符串
     * @return java.util.Date
     * @throws
     * @author secret
     * @date 2020/12/12 secret
     */
    public static Date parse(String date) {
        if (!StringUtils.hasText(date)) {
            return null;
        } else {
            try {
                return (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")).parse(date);
            } catch (ParseException var2) {
                return null;
            }
        }
    }

    /**
     * 日期型字符串转化为日期 格式
     */
    public static Date parseDate(Object str) {
        if (str == null) {
            return null;
        }
        try {
            return parseDate(str.toString(), parsePatterns);
        }
        catch (ParseException e) {
            return null;
        }
    }

    /**
     * @description: 将日期字符串按自定义格式化转化为Date对象
     * @param date 日期字符串
     * @param format 格式化字符串(例如:"yyyy-MM-dd HH:mm:ss")
     * @return java.util.Date
     * @throws
     * @author secret
     * @date 2020/12/12 secret
     */
    public static Date parse(String date, String format) {
        if (!StringUtils.hasText(date)) {
            return null;
        } else {
            try {
                return (new SimpleDateFormat(format)).parse(date);
            } catch (ParseException var3) {
                return null;
            }
        }
    }

    /**
     * @description: 将日期字符串格式化为"yyyy-MM-dd"的Date对象
     * @param date
     * @return java.util.Date
     * @throws
     * @author secret
     * @date 2020/12/12 secret
     */
    public static Date parseToYMD(String date) {
        try {
            return (new SimpleDateFormat("yyyy-MM-dd")).parse(date);
        } catch (ParseException var2) {
            return null;
        }
    }

    /**
     * @description: Date对象格式化为"yyyy-MM-dd HH:mm:ss"的字符串
     * @param date
     * @return java.lang.String
     * @throws
     * @author secret
     * @date 2020/12/12 secret
     */
    public static String format(Date date) {
        return date != null ? (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")).format(date) : "/";
    }

    /**
     * 将Date对象按自定义格式化为字符串
     * @param date
     * @param format
     * @return
     */
    public static String format(Date date, String format) {
        return (new SimpleDateFormat(format)).format(date);
    }

    /**
     * @description: 将Date对象增加年份
     * @param date
     * @param year
     * @return java.util.Date
     * @throws
     * @author secret
     * @date 2020/12/12 secret
     */
    public static Date addYear(Date date, int year) {
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        calendar.add(1, year);
        date = calendar.getTime();
        return date;
    }

    /**
     * @description: 将Date对象增加月份
     * @param date
     * @param month
     * @return java.util.Date
     * @throws
     * @author secret
     * @date 2020/12/12 secret
     */
    public static Date addMonth(Date date, int month) {
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        calendar.add(2, month);
        date = calendar.getTime();
        return date;
    }

    /**
     * @description: 将Date对象增加天数
     * @param date
     * @param day
     * @return java.util.Date
     * @throws
     * @author secret
     * @date 2020/12/12 secret
     */
    public static Date addDay(Date date, int day) {
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        calendar.add(5, day);
        date = calendar.getTime();
        return date;
    }

    /**
     * @description: 将Date对象增加小时
     * @param date
     * @param day
     * @return java.util.Date
     * @throws
     * @author secret
     * @date 2020/12/12 secret
     */
    public static Date addHour(Date date, int day) {
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        calendar.add(10, day);
        date = calendar.getTime();
        return date;
    }

    /**
     * @description: 将Date对象增加分钟
     * @param date
     * @param day
     * @return java.util.Date
     * @throws
     * @author secret
     * @date 2020/12/12 secret
     */
    public static Date addMinute(Date date, int day) {
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        calendar.add(12, day);
        date = calendar.getTime();
        return date;
    }

    /**
     * @description: 将Date对象增加周数
     * @param date
     * @param day
     * @return java.util.Date
     * @throws
     * @author secret
     * @date 2020/12/12 secret
     */
    public static Date addWeek(Date date, int day) {
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        calendar.add(3, day);
        date = calendar.getTime();
        return date;
    }

    /**
     * @description: 获取当前毫秒时间
     * @param
     * @return java.lang.Long
     * @throws
     * @author secret
     * @date 2020/12/12 secret
     */
    public static Long getTimestamp() {
        return System.currentTimeMillis();
    }

    /**
     * @description: 获取本周开始时间和结束时间
     * @param addEndDay 是否添加最后一天
     * @return java.util.Map<java.lang.String, java.lang.String>
     * @throws
     * @author secret
     * @date 2020/12/12 secret
     */
    public static Map<String, String> getCurrentWeek(boolean addEndDay) {
        Map<String, String> map = new HashMap(2);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Calendar cal = Calendar.getInstance();
        cal.setFirstDayOfWeek(2);
        int dayWeek = cal.get(7);
        if (dayWeek == 1) {
            dayWeek = 8;
        }

        cal.add(5, cal.getFirstDayOfWeek() - dayWeek);
        Date mondayDate = cal.getTime();
        String weekBegin = sdf.format(mondayDate);
        map.put("beginWeek", weekBegin);
        cal.add(5, 4 + cal.getFirstDayOfWeek());
        if (addEndDay) {
            cal.add(5, 1);
        }

        Date sundayDate = cal.getTime();
        String weekEnd = sdf.format(addDay(sundayDate, -1)) + " 23:59:59";
        map.put("endWeek", weekEnd);
        return map;
    }

    /**
     * @description: 获取本月开始时间和结束时间
     * @param addEndDay 是否添加最后一天
     * @return java.util.Map<java.lang.String, java.lang.String>
     * @throws
     * @author secret
     * @date 2020/12/12 secret
     */
    public static Map<String, String> getCurrentMonth(boolean addEndDay) {
        Map<String, String> map = new HashMap(2);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        map.put("beginMonth", format(new Date(), "yyyy-MM") + "-01");
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.set(5, calendar.getActualMaximum(5));
        if (addEndDay) {
            calendar.add(5, 1);
        }

        map.put("endMonth", sdf.format(calendar.getTime()));
        return map;
    }

    /**
     * @description: 获取任意时间当月的开始时间和结束时间
     * @param addEndDay 是否添加最后一天
     * @return java.util.Map<java.lang.String, java.lang.String>
     * @throws
     * @author secret
     * @date 2020/12/12 secret
     */
    public static Map<String, String> getAppointMonth(Date date, boolean addEndDay) {
        Map<String, String> map = new HashMap(2);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        map.put("beginMonth", format(date, "yyyy-MM") + "-01");
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(5, calendar.getActualMaximum(5));
        if (addEndDay) {
            calendar.add(5, 1);
        }

        map.put("endMonth", sdf.format(calendar.getTime()));
        return map;
    }

    /**
     * @description: 将秒转化为时间字符串
     * @param second
     * @return java.lang.String
     * @throws
     * @author secret
     * @date 2020/12/12 secret
     */
    public static String secondToTime(long second) {
        long days = second / 86400L;
        second %= 86400L;
        long hours = second / 3600L;
        second %= 3600L;
        long minutes = second / 60L;
        second %= 60L;
        return 0L < days ? days + "天" + hours + "小时" + minutes + "分" + second + "秒" : hours + "小时" + minutes + "分" + second + "秒";
    }

    /**
     * @description: 获得日期的年份
     * @param date
     * @return int
     * @throws
     * @author secret
     * @date 2020/12/12 secret
     */
    public static int getYear(Date date) {
        SimpleDateFormat sdf = new SimpleDateFormat("YYYY");
        return Integer.valueOf(sdf.format(date));
    }

    /**
     * @description: 获取某年的第一天
     * @param year 年份
     * @return java.util.Date
     * @throws
     * @author secret
     * @date 2020/12/12 secret
     */
    public static Date getYearFirst(int year) {
        Calendar calendar = Calendar.getInstance();
        calendar.clear();
        calendar.set(1, year);
        Date currYearFirst = calendar.getTime();
        return currYearFirst;
    }

    /**
     * @description: 获取某年最后一天
     * @param year
     * @return java.util.Date
     * @throws
     * @author secret
     * @date 2020/12/12 secret
     */
    public static Date getYearLast(int year) {
        Calendar calendar = Calendar.getInstance();
        calendar.clear();
        calendar.set(1, year);
        calendar.roll(6, -1);
        Date currYearLast = calendar.getTime();
        return currYearLast;
    }

    /**
     * @description: 将Date对象转化为LocalDateTime对象
     * @param date
     * @return java.time.LocalDateTime
     * @throws
     * @author secret
     * @date 2020/12/12 secret
     */
    public static LocalDateTime dateToLocalDateTime(Date date){
        Instant instant = date.toInstant();
        ZoneId zoneId = ZoneId.systemDefault();
        LocalDateTime localDateTime = instant.atZone(zoneId).toLocalDateTime();
        return localDateTime;
    }

    public static LocalDateTime parseLocalDateTime(String dateStr){
        String patten = getDateFormat(dateStr);
        Date date = parse(dateStr,patten);
        return dateToLocalDateTime(date);
    }

    /**
     * @description: Date转LocalDate
     * @param date
     * @return java.time.LocalDateTime
     * @throws
     * @author secret
     * @date 2022/6/10 secret
     */
    public static LocalDate dateToLocalDate(Date date){
        Instant instant = date.toInstant();
        ZoneId zoneId = ZoneId.systemDefault();
        LocalDate localDate = instant.atZone(zoneId).toLocalDate();
        return localDate;
    }

    public static LocalDateTime parseLocalDate(String dateStr){
        String patten = getDateFormat(dateStr);
        Date date = parse(dateStr,patten);
        return dateToLocalDateTime(date);
    }

    /**
     * 日期路径 即年/月/日 如2018/08/08
     */
    public static final String datePath() {
        Date now = new Date();
        return DateFormatUtils.format(now, "yyyy/MM/dd");
    }

    /**
     * 日期路径 即年/月/日 如20180808
     */
    public static final String dateTime() {
        Date now = new Date();
        return DateFormatUtils.format(now, "yyyyMMdd");
    }

    public static final String parseDateToStr(final String format, final Date date) {
        return new SimpleDateFormat(format).format(date);
    }

    /**
     * 计算两个时间差
     * return xx天xx小时xx分钟
     */
    public static String getDatePoor(Date endDate, Date nowDate) {
        long nd = 1000 * 24 * 60 * 60;
        long nh = 1000 * 60 * 60;
        long nm = 1000 * 60;
        // long ns = 1000;
        // 获得两个时间的毫秒时间差异
        long diff = endDate.getTime() - nowDate.getTime();
        // 计算差多少天
        long day = diff / nd;
        // 计算差多少小时
        long hour = diff % nd / nh;
        // 计算差多少分钟
        long min = diff % nd % nh / nm;
        // 计算差多少秒//输出结果
        // long sec = diff % nd % nh % nm / ns;
        return day + "天" + hour + "小时" + min + "分钟";
    }

    /**
     * 常规自动日期格式识别
     * @param str 时间字符串
     * @return String
     * @author secret
     * 如:1998-09-27 -> yyyy-MM-dd
     */
    public static String getDateFormat(String str){
        boolean year = false;
        Pattern pattern = Pattern.compile("^[-\\+]?[\\d]*$");
        if(pattern.matcher(str.substring(0, 4)).matches()) {
            year = true;
        }
        StringBuilder sb = new StringBuilder();
        int index = 0;
        if(!year) {
            if(str.contains("月") || str.contains("-") || str.contains("/")) {
                if(Character.isDigit(str.charAt(0))) {
                    index = 1;
                }
            }else {
                index = 3;
            }
        }
        for (int i = 0; i < str.length(); i++) {
            char chr = str.charAt(i);
            if(Character.isDigit(chr)) {
                if(index==0) {
                    sb.append("y");
                }
                if(index==1) {
                    sb.append("M");
                }
                if(index==2) {
                    sb.append("d");
                }
                if(index==3) {
                    sb.append("H");
                }
                if(index==4) {
                    sb.append("m");
                }
                if(index==5) {
                    sb.append("s");
                }
                if(index==6) {
                    sb.append("S");
                }
            }else {
                if(i>0) {
                    char lastChar = str.charAt(i-1);
                    if(Character.isDigit(lastChar)) {
                        index++;
                    }
                }
                sb.append(chr);
            }
        }
        return sb.toString();
    }

    /**
     * 计算时间差
     *
     * @param endDate 最后时间
     * @param startTime 开始时间
     * @return 时间差（天/小时/分钟）
     */
    public static String timeDistance(Date endDate, Date startTime) {
        long nd = 1000 * 24 * 60 * 60;
        long nh = 1000 * 60 * 60;
        long nm = 1000 * 60;
        // long ns = 1000;
        // 获得两个时间的毫秒时间差异
        long diff = endDate.getTime() - startTime.getTime();
        // 计算差多少天
        long day = diff / nd;
        // 计算差多少小时
        long hour = diff % nd / nh;
        // 计算差多少分钟
        long min = diff % nd % nh / nm;
        // 计算差多少秒//输出结果
        // long sec = diff % nd % nh % nm / ns;
        return day + "天" + hour + "小时" + min + "分钟";
    }

    /**
     * 增加 LocalDateTime ==> Date
     */
    public static Date toDate(LocalDateTime temporalAccessor)
    {
        ZonedDateTime zdt = temporalAccessor.atZone(ZoneId.systemDefault());
        return Date.from(zdt.toInstant());
    }

    /**
     * 增加 LocalDate ==> Date
     */
    public static Date toDate(LocalDate temporalAccessor)
    {
        LocalDateTime localDateTime = LocalDateTime.of(temporalAccessor, LocalTime.of(0, 0, 0));
        ZonedDateTime zdt = localDateTime.atZone(ZoneId.systemDefault());
        return Date.from(zdt.toInstant());
    }

}
